"""运行模块，用于管理 Ollama 服务的执行"""

import os
import subprocess
import time
import atexit

from .utils.display import display


class OllamaService:
    """管理Ollama服务的生命周期"""

    def __init__(self):
        """
        功能：初始化Ollama服务管理器
        :return: 无
        """
        self.service_process = None

    def start(self):
        """
        功能：启动Ollama服务
        :return: 无
        """
        if self.is_running():
            display("🔧🔧 Ollama 服务已在运行")
            return

        display("🛠🛠🛠 正在启动 Ollama 服务...")
        try:
            # 不使用with语句原因：需要保持服务进程长期运行
            # pylint: disable=consider-using-with
            self.service_process = subprocess.Popen(
                ["ollama", "serve"],
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                text=True,
            )
            display("⏳⏳⏳ 等待服务初始化...")
            time.sleep(2)

            if self.is_running():
                display("✅ Ollama 服务已启动")
                # 注册退出时自动停止服务
                atexit.register(self.stop)
            else:
                display("🛑🛑🛑 Ollama 服务启动失败")
                self.log_output()
                raise RuntimeError("无法启动 Ollama 服务")
        except (OSError, subprocess.SubprocessError) as e:
            display(f"❌❌ Ollama 服务启动失败: {e}")
            if self.service_process:
                try:
                    self.service_process.terminate()
                    self.service_process.wait(timeout=2)
                # 限定只捕获OS相关异常
                except (OSError, subprocess.TimeoutExpired, ValueError):
                    pass
            raise

    def stop(self):
        """
        功能：停止Ollama服务
        :return: 无
        """
        if self.service_process is None:
            return

        display("🛑🛑🛑 正在停止 Ollama 服务...")
        try:
            # 使用上下文管理器确保资源被正确释放
            with self.service_process:
                if self.service_process.poll() is None:
                    self.service_process.terminate()
                    try:
                        display("⏳⏳⏳ 等待服务停止...")
                        self.service_process.wait(timeout=5)
                        display("✅ Ollama 服务已停止")
                    except subprocess.TimeoutExpired:
                        display("⚠️ 等待服务停止超时，尝试强制终止")
                        self.service_process.kill()
                        self.service_process.wait()
        finally:
            self.service_process = None

    def is_running(self):
        """
        功能：检查Ollama服务是否正在运行
        :return: 如果服务正在运行返回True，否则返回False
        """
        try:
            result = subprocess.run(
                ["curl", "-s", "http://localhost:11434/"],
                capture_output=True,
                text=True,
                timeout=2,
                check=False,
            )
            return "Ollama is running" in result.stdout
        except subprocess.TimeoutExpired:
            return False
        except (OSError, subprocess.SubprocessError):
            return False

    def log_output(self):
        """
        功能：记录服务输出日志
        :return: 无
        """
        if self.service_process is None:
            return

        display("📄📄 服务输出日志:")
        try:
            while True:
                line = self.service_process.stdout.readline()
                if not line and self.service_process.poll() is not None:
                    break
                if line:
                    display(f"   | {line.strip()}")
        except ValueError:  # 当I/O在关闭的文件上操作时
            pass
        display("--------------------")


class Runner:
    """使用优化参数执行Ollama模型"""

    def __init__(self, config):
        """
        功能：初始化模型运行器
        :param config: 应用的配置信息
        :return: 无
        """
        self.config = config
        self.service = OllamaService()

    def run(self, model_tag, params):
        """
        功能：运行指定模型
        :param model_tag: 要运行的模型标签
        :param params: 包含运行参数的字典
        :return: 无
        """
        try:
            self.service.start()
            display("✅ 启动LLM服务... (按Ctrl+C退出)")

            # 设置环境变量
            env = os.environ.copy()
            env["OLLAMA_NUM_THREADS"] = str(params["threads"])
            env["OLLAMA_NUM_CTX"] = str(params["ctx_size"])

            if params.get("gpu_layers", 0) > 0:
                env["OLLAMA_GPU_LAYERS"] = str(params["gpu_layers"])
                display(f"💡💡 使用GPU加速，设置GPU层数为: {params['gpu_layers']}")
            else:
                env["OLLAMA_GPU_LAYERS"] = "0"
                display("💡💡 纯CPU模式运行，禁用GPU加速")

            cmd = ["ollama", "run", model_tag]
            display(f"执行命令: {' '.join(cmd)}")
            display(
                f"环境配置: [线程数: {params['threads']}, "
                f"上下文窗口: {params['ctx_size']}"
                + (
                    f", GPU加速层: {params['gpu_layers']}"
                    if params.get("gpu_layers")
                    else ""
                )
            )

            # 运行模型
            subprocess.run(cmd, env=env, check=False)
        except KeyboardInterrupt:
            display("\n🛑🛑🛑 用户中断")
        except (RuntimeError, OSError, subprocess.SubprocessError) as e:
            display(f"❌❌ 运行失败: {e}")
            self.service.log_output()
            raise
        finally:
            # 确保服务被停止
            self.stop_service()

    def stop_service(self):
        """
        功能：停止LLM服务
        :return: 无
        """
        self.service.stop()
